using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using System.Drawing;
using System.Windows.Forms;
using System.Text.RegularExpressions;

namespace SimplIDE
{
  public class SyntaxHighlighter
  {
    public void Ident(RichTextBox textBox)
    {
      int start = textBox.SelectionStart;
      string code = textBox.Text;
      int ident = tokenizer.GetIdent(code, start);
      string spaces = string.Empty;
      for (int i = 0; i < ident; ++i)
        spaces += "  ";
      textBox.SelectedText += spaces;
    }

    public void Colorize(RichTextBox textBox, int pos, int len)
    {
      int start = textBox.SelectionStart;
      DateTime timer = DateTime.Now;
      List<CPPTokenizer.Token> changedTokens = null;
      if (pos == 0 && (len == textBox.Text.Length || len == 0))
      {
        textBox.SelectionStart = 0;
        textBox.SelectionLength = textBox.Text.Length;
        textBox.SelectionColor = Colors.Text;
        tokenizer.Rebuild(textBox.Text);
        changedTokens = tokenizer.Tokens;
      }
      else
      {
        string code = textBox.Text;
        changedTokens = tokenizer.BuildFrom(code, pos);
      }
      int elapsed = (DateTime.Now - timer).Milliseconds;
      if (elapsed > slowestColorize)
        System.Diagnostics.Debug.WriteLine(string.Format("(DEBUG) Colorize: {0} ms", elapsed));
      slowestColorize = Math.Max(elapsed, slowestColorize);
      //tokenizer.Dump(false);

      foreach (CPPTokenizer.Token token in changedTokens)
      {
        //if (!(pos == 0 && (len == textBox.Text.Length || len == 0)))
        //  System.Diagnostics.Debug.WriteLine(string.Format("TOKENCOLOR {0}:'{1}' len:{4} [{2},{3}]", token.start, textBox.Text.Substring(token.start, token.length), token.id.ToString(), token.sub.ToString(), token.length));
        if (token.id == CPPTokenizer.TokenId.Unknown || token.id == CPPTokenizer.TokenId.Whitespace)
          continue;
        textBox.SelectionStart = token.start;
        textBox.SelectionLength = token.length;
        if (token.id == CPPTokenizer.TokenId.Comment)
          textBox.SelectionColor = Colors.Comment;
        else if (token.id == CPPTokenizer.TokenId.Keyword || token.id == CPPTokenizer.TokenId.PreprocessorKeyword)
          textBox.SelectionColor = Colors.Keyword;
        else if (token.sub == CPPTokenizer.TokenSubId.Function)
          textBox.SelectionColor = Colors.Identifier;
        else if (token.sub == CPPTokenizer.TokenSubId.Defined || token.sub == CPPTokenizer.TokenSubId.Enum)
          textBox.SelectionColor = Colors.Define;
        else if (token.sub == CPPTokenizer.TokenSubId.Type || token.sub == CPPTokenizer.TokenSubId.Namespace)
          textBox.SelectionColor = Colors.Class;
        else if (token.id == CPPTokenizer.TokenId.Literal)
        {
          if (token.sub == CPPTokenizer.TokenSubId.StringLiteral)
            textBox.SelectionColor = Colors.String;
          else if (token.sub != CPPTokenizer.TokenSubId.CharLiteral && token.sub != CPPTokenizer.TokenSubId.IncludeLiteral)
            textBox.SelectionColor = Colors.Number;
          else
            textBox.SelectionColor = Colors.Text;
        }
        else
          textBox.SelectionColor = Colors.Text;
      }
      textBox.SelectionStart = start;
      textBox.SelectionLength = 0;
    }

    public void Save(string file)
    {
      try
      {
        XmlSerializer serializer = new XmlSerializer(typeof(SyntaxHighlighter));
        StreamWriter writer = new StreamWriter(file);
        serializer.Serialize(writer, this);
      }
      catch
      {
      }
    }

    static public SyntaxHighlighter Load(string file)
    {
      SyntaxHighlighter syntaxHighlighter = new SyntaxHighlighter();
      if (!File.Exists(file))
        return syntaxHighlighter;
      try
      {
        XmlSerializer serializer = new XmlSerializer(typeof(SyntaxHighlighter));
        using (StreamReader reader = new StreamReader(file))
          syntaxHighlighter = serializer.Deserialize(reader) as SyntaxHighlighter;
        return syntaxHighlighter;
      }
      catch
      {
        return syntaxHighlighter;
      }
    }

    public class ColorSettings
    {
      [XmlIgnore] public Color Background { get { return ColorTranslator.FromHtml(BackgroundColor); } }
      [XmlIgnore] public Color Text { get { return ColorTranslator.FromHtml(TextColor); } }
      [XmlIgnore] public Color Keyword { get { return ColorTranslator.FromHtml(KeywordColor); } }
      [XmlIgnore] public Color Number { get { return ColorTranslator.FromHtml(NumberColor); } }
      [XmlIgnore] public Color String { get { return ColorTranslator.FromHtml(StringColor); } }
      [XmlIgnore] public Color Comment { get { return ColorTranslator.FromHtml(CommentColor); } }
      [XmlIgnore] public Color Identifier { get { return ColorTranslator.FromHtml(IdentifierColor); } }
      [XmlIgnore] public Color Define { get { return ColorTranslator.FromHtml(DefineColor); } }
      [XmlIgnore] public Color Class { get { return ColorTranslator.FromHtml(ClassColor); } }

      public string BackgroundColor = "#FFFFFF";
      public string TextColor = "#606060";
      public string KeywordColor = "#1C5D97";
      public string NumberColor = "#000000";
      public string StringColor = "#0000C0";
      public string CommentColor = "#006000";
      public string IdentifierColor = "#600000";
      public string DefineColor = "#FF46FF";
      public string ClassColor = "#7D9EC0";
    }

    public ColorSettings Colors = new ColorSettings();

    [XmlIgnore]
    string keywords = string.Empty;
    [XmlIgnore]
    CPPTokenizer tokenizer = new CPPTokenizer();
    [XmlIgnore]
    int slowestColorize = 0;
  }
}
